// internal/service/vm_service.go
package service

import (
	"context"
	"fmt"
	"sync"
	"time"

	"github.com/sirupsen/logrus"
	"libvirt.org/go/libvirt"

	"virt-manager-go/internal/domain"
	// "virt-manager-go/internal/libvirt/pool"
	"virt-manager-go/internal/libvirt/xmlbuilder"
)

type vmService struct {
	connMgr    domain.ConnectionManager
	xmlBuilder domain.XMLBuilder
	logger     *logrus.Logger

	// 性能指标缓存
	metricsMu    sync.RWMutex
	metricsCache map[string]*domain.VMMetrics
}

func NewVMService(connMgr domain.ConnectionManager, logger *logrus.Logger) domain.VMService {
	return &vmService{
		connMgr:      connMgr,
		xmlBuilder:   xmlbuilder.NewXMLBuilder(),
		logger:       logger,
		metricsCache: make(map[string]*domain.VMMetrics),
	}
}

// CreateVM 创建虚拟机（支持 ISO、PXE、导入磁盘）
func (s *vmService) CreateVM(ctx context.Context, connID string, config *domain.VMCreateConfig) (*domain.VMInfo, error) {
	s.logger.WithFields(logrus.Fields{
		"connection": connID,
		"vm_name":    config.Name,
		"cpus":       config.CPUs,
		"memory":     config.Memory,
	}).Info("Creating new virtual machine")

	conn, err := s.connMgr.GetConnection(connID)
	if err != nil {
		return nil, fmt.Errorf("failed to get connection: %w", err)
	}

	// 验证虚拟机名称是否已存在
	if exists, err := s.vmExists(conn, config.Name); err != nil {
		return nil, fmt.Errorf("failed to check VM existence: %w", err)
	} else if exists {
		return nil, fmt.Errorf("VM with name '%s' already exists", config.Name)
	}

	// 构建 XML
	xmlData, err := s.xmlBuilder.BuildVMXML(config)
	if err != nil {
		return nil, fmt.Errorf("failed to build VM XML: %w", err)
	}

	s.logger.WithField("xml", xmlData).Debug("Generated VM XML")

	// 根据安装方式决定是否立即启动
	var dom *libvirt.Domain
	if config.InstallISO != "" || config.InstallPXE {
		// ISO 或 PXE 安装：创建并启动
		dom, err = conn.DomainCreateXML(xmlData, libvirt.DOMAIN_START_PAUSED)
		if err != nil {
			return nil, fmt.Errorf("failed to create and start VM: %w", err)
		}
		defer dom.Free()

		// 如果需要，可以立即恢复（取消暂停）
		if err := dom.Resume(); err != nil {
			s.logger.WithError(err).Warn("Failed to resume VM after creation")
		}
	} else {
		// 导入磁盘：仅定义，不启动
		dom, err = conn.DomainDefineXML(xmlData)
		if err != nil {
			return nil, fmt.Errorf("failed to define VM: %w", err)
		}
		defer dom.Free()
	}

	// 设置自动启动
	if config.Autostart {
		if err := dom.SetAutostart(true); err != nil {
			s.logger.WithError(err).Warn("Failed to set autostart")
		}
	}

	// 设置元数据
	if len(config.Metadata) > 0 {
		for key, value := range config.Metadata {
			if err := s.setMetadata(dom, key, value); err != nil {
				s.logger.WithError(err).Warnf("Failed to set metadata %s", key)
			}
		}
	}

	s.logger.WithField("vm_name", config.Name).Info("VM created successfully")

	return s.domainToVMInfo(dom)
}

// ListVMs 列出所有虚拟机
func (s *vmService) ListVMs(ctx context.Context, connID string) ([]*domain.VMInfo, error) {
	conn, err := s.connMgr.GetConnection(connID)
	if err != nil {
		return nil, err
	}

	// 获取所有域（包括运行中和已定义的）
	domains, err := conn.ListAllDomains(libvirt.CONNECT_LIST_DOMAINS_ACTIVE | libvirt.CONNECT_LIST_DOMAINS_INACTIVE)
	if err != nil {
		return nil, fmt.Errorf("failed to list domains: %w", err)
	}

	vms := make([]*domain.VMInfo, 0, len(domains))
	for _, dom := range domains {
		vmInfo, err := s.domainToVMInfo(&dom)
		dom.Free()
		if err != nil {
			s.logger.WithError(err).Warn("Failed to convert domain to VMInfo")
			continue
		}
		vms = append(vms, vmInfo)
	}

	return vms, nil
}

// GetVM 获取单个虚拟机信息
func (s *vmService) GetVM(ctx context.Context, connID, vmName string) (*domain.VMInfo, error) {
	conn, err := s.connMgr.GetConnection(connID)
	if err != nil {
		return nil, err
	}

	dom, err := conn.LookupDomainByName(vmName)
	if err != nil {
		return nil, fmt.Errorf("VM not found: %w", err)
	}
	defer dom.Free()

	return s.domainToVMInfo(dom)
}

// StartVM 启动虚拟机
func (s *vmService) StartVM(ctx context.Context, connID, vmName string) error {
	dom, err := s.getDomain(connID, vmName)
	if err != nil {
		return fmt.Errorf("failed to get domain: %w", err)
	}
	defer dom.Free()

	state, _, err := dom.GetState()
	if err != nil {
		return fmt.Errorf("failed to get VM state: %w", err)
	}

	if state == libvirt.DOMAIN_RUNNING {
		return fmt.Errorf("VM is already running")
	}

	if err := dom.Create(); err != nil {
		// 记录详细错误信息
		s.logger.WithFields(logrus.Fields{
			"vm_name": vmName,
			"conn_id": connID,
			"error":   err.Error(),
		}).Error("Failed to start VM")

		return fmt.Errorf("failed to start VM: %w", err)
	}

	s.logger.WithField("vm_name", vmName).Info("VM started successfully")
	return nil
}

// ShutdownVM 关闭虚拟机
func (s *vmService) ShutdownVM(ctx context.Context, connID, vmName string, force bool) error {
	dom, err := s.getDomain(connID, vmName)
	if err != nil {
		return err
	}
	defer dom.Free()

	if force {
		if err := dom.Destroy(); err != nil {
			return fmt.Errorf("failed to force shutdown VM: %w", err)
		}
		s.logger.WithField("vm_name", vmName).Info("VM force shutdown")
	} else {
		if err := dom.Shutdown(); err != nil {
			return fmt.Errorf("failed to shutdown VM: %w", err)
		}
		s.logger.WithField("vm_name", vmName).Info("VM shutdown initiated")
	}

	return nil
}

// RebootVM 重启虚拟机
func (s *vmService) RebootVM(ctx context.Context, connID, vmName string) error {
	dom, err := s.getDomain(connID, vmName)
	if err != nil {
		return err
	}
	defer dom.Free()

	if err := dom.Reboot(libvirt.DOMAIN_REBOOT_DEFAULT); err != nil {
		return fmt.Errorf("failed to reboot VM: %w", err)
	}

	s.logger.WithField("vm_name", vmName).Info("VM rebooted")
	return nil
}

// SuspendVM 暂停虚拟机
func (s *vmService) SuspendVM(ctx context.Context, connID, vmName string) error {
	dom, err := s.getDomain(connID, vmName)
	if err != nil {
		return err
	}
	defer dom.Free()

	if err := dom.Suspend(); err != nil {
		return fmt.Errorf("failed to suspend VM: %w", err)
	}

	s.logger.WithField("vm_name", vmName).Info("VM suspended")
	return nil
}

// ResumeVM 恢复虚拟机
func (s *vmService) ResumeVM(ctx context.Context, connID, vmName string) error {
	dom, err := s.getDomain(connID, vmName)
	if err != nil {
		return err
	}
	defer dom.Free()

	if err := dom.Resume(); err != nil {
		return fmt.Errorf("failed to resume VM: %w", err)
	}

	s.logger.WithField("vm_name", vmName).Info("VM resumed")
	return nil
}

// DeleteVM 删除虚拟机
func (s *vmService) DeleteVM(ctx context.Context, connID, vmName string, removeStorage bool) error {
	dom, err := s.getDomain(connID, vmName)
	if err != nil {
		return err
	}
	defer dom.Free()

	// 如果正在运行，先强制关闭
	state, _, err := dom.GetState()
	if err != nil {
		return fmt.Errorf("failed to get VM state: %w", err)
	}
	if state == libvirt.DOMAIN_RUNNING {
		if err := dom.Destroy(); err != nil {
			return fmt.Errorf("failed to stop VM before deletion: %w", err)
		}
	}

	// 删除存储（如果需要）
	if removeStorage {
		if err := s.removeVMStorage(dom); err != nil {
			s.logger.WithError(err).Warn("Failed to remove VM storage")
		}
	}

	// 取消定义虚拟机
	if err := dom.Undefine(); err != nil {
		return fmt.Errorf("failed to undefine VM: %w", err)
	}

	s.logger.WithField("vm_name", vmName).Info("VM deleted successfully")
	return nil
}

// CloneVM 克隆虚拟机
func (s *vmService) CloneVM(ctx context.Context, connID, srcVM, destVM string) error {
	conn, err := s.connMgr.GetConnection(connID)
	if err != nil {
		return err
	}

	srcDom, err := conn.LookupDomainByName(srcVM)
	if err != nil {
		return fmt.Errorf("source VM not found: %w", err)
	}
	defer srcDom.Free()

	// 确保源虚拟机已关闭
	state, _, err := srcDom.GetState()
	if err != nil {
		return fmt.Errorf("failed to get source VM state: %w", err)
	}
	if state == libvirt.DOMAIN_RUNNING {
		return fmt.Errorf("cannot clone running VM, please shut it down first")
	}

	// 获取源虚拟机 XML
	srcXML, err := srcDom.GetXMLDesc(0)
	if err != nil {
		return fmt.Errorf("failed to get source VM XML: %w", err)
	}

	// 修改 XML（名称、UUID、MAC 地址等）
	clonedXML, err := s.xmlBuilder.CloneVMXML(srcXML, destVM)
	if err != nil {
		return fmt.Errorf("failed to clone VM XML: %w", err)
	}

	// 克隆磁盘
	if err := s.cloneVMDisks(conn, srcDom, destVM); err != nil {
		return fmt.Errorf("failed to clone VM disks: %w", err)
	}

	// 定义新虚拟机
	destDom, err := conn.DomainDefineXML(clonedXML)
	if err != nil {
		return fmt.Errorf("failed to define cloned VM: %w", err)
	}
	defer destDom.Free()

	s.logger.WithFields(logrus.Fields{
		"source": srcVM,
		"dest":   destVM,
	}).Info("VM cloned successfully")

	return nil
}

// UpdateVMConfig 更新虚拟机配置
func (s *vmService) UpdateVMConfig(ctx context.Context, connID, vmName string, config *domain.VMConfig) error {
	dom, err := s.getDomain(connID, vmName)
	if err != nil {
		return err
	}
	defer dom.Free()

	// 检查虚拟机是否正在运行
	state, _, err := dom.GetState()
	if err != nil {
		return fmt.Errorf("failed to get VM state: %w", err)
	}
	isRunning := state == libvirt.DOMAIN_RUNNING

	// 更新 CPU（需要关机）
	if config.CPUs != nil && !isRunning {
		if err := dom.SetVcpusFlags(*config.CPUs, libvirt.DOMAIN_VCPU_CONFIG); err != nil {
			return fmt.Errorf("failed to update CPUs: %w", err)
		}
	}

	// 更新内存（可以热更新最大内存）
	if config.MaxMemory != nil {
		if err := dom.SetMaxMemory(*config.MaxMemory); err != nil {
			return fmt.Errorf("failed to update max memory: %w", err)
		}
	}
	if config.Memory != nil && !isRunning {
		if err := dom.SetMemory(*config.Memory); err != nil {
			return fmt.Errorf("failed to update memory: %w", err)
		}
	}

	// 更新自动启动
	if config.Autostart != nil {
		if err := dom.SetAutostart(*config.Autostart); err != nil {
			return fmt.Errorf("failed to update autostart: %w", err)
		}
	}

	s.logger.WithField("vm_name", vmName).Info("VM configuration updated")
	return nil
}

// GetVMXML 获取虚拟机 XML
func (s *vmService) GetVMXML(ctx context.Context, connID, vmName string) (string, error) {
	dom, err := s.getDomain(connID, vmName)
	if err != nil {
		return "", err
	}
	defer dom.Free()

	xmlData, err := dom.GetXMLDesc(0)
	if err != nil {
		return "", fmt.Errorf("failed to get VM XML: %w", err)
	}

	return xmlData, nil
}

// ImportVMXML 导入 XML 创建虚拟机
func (s *vmService) ImportVMXML(ctx context.Context, connID string, xmlData string) (*domain.VMInfo, error) {
	conn, err := s.connMgr.GetConnection(connID)
	if err != nil {
		return nil, err
	}

	dom, err := conn.DomainDefineXML(xmlData)
	if err != nil {
		return nil, fmt.Errorf("failed to import VM XML: %w", err)
	}
	defer dom.Free()

	s.logger.Info("VM imported from XML successfully")
	return s.domainToVMInfo(dom)
}

// GetVMMetrics 获取虚拟机性能指标
func (s *vmService) GetVMMetrics(ctx context.Context, connID, vmName string) (*domain.VMMetrics, error) {
	dom, err := s.getDomain(connID, vmName)
	if err != nil {
		return nil, err
	}
	defer dom.Free()

	metrics := &domain.VMMetrics{
		Timestamp: time.Now(),
	}

	// 获取 CPU 时间
	info, err := dom.GetInfo()
	if err != nil {
		return nil, fmt.Errorf("failed to get domain info: %w", err)
	}
	metrics.CPUTime = info.CpuTime
	metrics.MemoryUsed = info.Memory

	// 计算 CPU 百分比（需要两次采样）
	cacheKey := fmt.Sprintf("%s:%s", connID, vmName)
	s.metricsMu.RLock()
	lastMetrics := s.metricsCache[cacheKey]
	s.metricsMu.RUnlock()

	if lastMetrics != nil {
		timeDelta := metrics.Timestamp.Sub(lastMetrics.Timestamp).Seconds()
		cpuDelta := float64(metrics.CPUTime-lastMetrics.CPUTime) / 1e9 // 转换为秒
		metrics.CPUPercent = (cpuDelta / timeDelta) / float64(info.NrVirtCpu) * 100
	}

	// 获取磁盘和网络统计
	if err := s.collectDiskStats(dom, metrics); err != nil {
		s.logger.WithError(err).Warn("Failed to collect disk stats")
	}
	if err := s.collectNetworkStats(dom, metrics); err != nil {
		s.logger.WithError(err).Warn("Failed to collect network stats")
	}

	// 缓存当前指标
	s.metricsMu.Lock()
	s.metricsCache[cacheKey] = metrics
	s.metricsMu.Unlock()

	return metrics, nil
}

// StreamVMMetrics 流式获取虚拟机性能指标
func (s *vmService) StreamVMMetrics(ctx context.Context, connID, vmName string, interval time.Duration) (<-chan *domain.VMMetrics, error) {
	metricsCh := make(chan *domain.VMMetrics, 10)

	go func() {
		defer close(metricsCh)
		ticker := time.NewTicker(interval)
		defer ticker.Stop()

		for {
			select {
			case <-ctx.Done():
				return
			case <-ticker.C:
				metrics, err := s.GetVMMetrics(ctx, connID, vmName)
				if err != nil {
					s.logger.WithError(err).Error("Failed to get VM metrics")
					continue
				}
				select {
				case metricsCh <- metrics:
				case <-ctx.Done():
					return
				}
			}
		}
	}()

	return metricsCh, nil
}

// === 辅助方法 ===

func (s *vmService) getDomain(connID, vmName string) (*libvirt.Domain, error) {
	conn, err := s.connMgr.GetConnection(connID)
	if err != nil {
		return nil, err
	}

	dom, err := conn.LookupDomainByName(vmName)
	if err != nil {
		return nil, fmt.Errorf("VM not found: %w", err)
	}

	return dom, nil
}

func (s *vmService) vmExists(conn *libvirt.Connect, name string) (bool, error) {
	_, err := conn.LookupDomainByName(name)
	if err != nil {
		if err.(libvirt.Error).Code == libvirt.ERR_NO_DOMAIN {
			return false, nil
		}
		return false, err
	}
	return true, nil
}

func (s *vmService) domainToVMInfo(dom *libvirt.Domain) (*domain.VMInfo, error) {
	name, err := dom.GetName()
	if err != nil {
		return nil, err
	}

	uuid, err := dom.GetUUIDString()
	if err != nil {
		return nil, err
	}

	id, err := dom.GetID()
	if err != nil {
		// 如果获取Domain ID失败，使用最大uint值表示无效ID
		// 在libvirt中，无效的domain ID通常表示虚拟机未运行
		id = ^uint(0) // 这是libvirt中表示无效ID的值
	}

	info, err := dom.GetInfo()
	if err != nil {
		return nil, err
	}

	autostart, err := dom.GetAutostart()
	if err != nil {
		autostart = false
	}

	persistent, err := dom.IsPersistent()
	if err != nil {
		persistent = false
	}

	state := s.libvirtStateToVMState(libvirt.DomainState(info.State))

	vmInfo := &domain.VMInfo{
		ID:         fmt.Sprintf("%d", id),
		Name:       name,
		UUID:       uuid,
		State:      state,
		CPUs:       info.NrVirtCpu,
		Memory:     info.Memory,
		MaxMemory:  info.MaxMem,
		Autostart:  autostart,
		Persistent: persistent,
	}

	// 解析 XML 获取详细信息
	xmlData, err := dom.GetXMLDesc(0)
	if err == nil {
		if config, err := s.xmlBuilder.ParseVMXML(xmlData); err == nil {
			// 填充更多详细信息
			vmInfo.OSType = config.OSType
			vmInfo.Architecture = config.Architecture
		}
	}

	return vmInfo, nil
}

func (s *vmService) libvirtStateToVMState(state libvirt.DomainState) domain.VMState {
	switch state {
	case libvirt.DOMAIN_RUNNING:
		return domain.VMStateRunning
	case libvirt.DOMAIN_PAUSED:
		return domain.VMStatePaused
	case libvirt.DOMAIN_SHUTDOWN:
		return domain.VMStateShutdown
	case libvirt.DOMAIN_SHUTOFF:
		return domain.VMStateShutoff
	case libvirt.DOMAIN_CRASHED:
		return domain.VMStateCrashed
	default:
		return domain.VMStateShutoff
	}
}

func (s *vmService) setMetadata(dom *libvirt.Domain, key, value string) error {
	uri := "http://virt-manager-go/metadata"
	return dom.SetMetadata(libvirt.DOMAIN_METADATA_ELEMENT,
		fmt.Sprintf("<%s>%s</%s>", key, value, key),
		key, uri, libvirt.DOMAIN_AFFECT_CONFIG)
}

func (s *vmService) removeVMStorage(dom *libvirt.Domain) error {
	xmlData, err := dom.GetXMLDesc(0)
	if err != nil {
		return err
	}

	// 解析 XML 获取磁盘列表
	config, err := s.xmlBuilder.ParseVMXML(xmlData)
	if err != nil {
		return err
	}

	// 删除每个磁盘
	for _, disk := range config.Disks {
		if disk.Source != "" {
			s.logger.WithField("disk", disk.Source).Info("Removing disk")
			// 这里需要调用存储池 API 删除卷
			// 为简化示例，这里仅记录日志
		}
	}

	return nil
}

func (s *vmService) cloneVMDisks(conn *libvirt.Connect, srcDom *libvirt.Domain, destVM string) error {
	xmlData, err := srcDom.GetXMLDesc(0)
	if err != nil {
		return err
	}

	config, err := s.xmlBuilder.ParseVMXML(xmlData)
	if err != nil {
		return err
	}

	for i, disk := range config.Disks {
		if disk.Source != "" && disk.Device == "disk" {
			newPath := fmt.Sprintf("/var/lib/libvirt/images/%s-disk%d.qcow2", destVM, i)

			// 使用 qemu-img 或存储池 API 克隆磁盘
			s.logger.WithFields(logrus.Fields{
				"source": disk.Source,
				"dest":   newPath,
			}).Info("Cloning disk")

			// 实际实现需要调用存储池 API
			// 这里仅作示意
		}
	}

	return nil
}

func (s *vmService) collectDiskStats(dom *libvirt.Domain, metrics *domain.VMMetrics) error {
	xmlData, err := dom.GetXMLDesc(0)
	if err != nil {
		return err
	}

	config, err := s.xmlBuilder.ParseVMXML(xmlData)
	if err != nil {
		return err
	}

	var totalRead, totalWrite uint64
	for _, disk := range config.Disks {
		if disk.Target != "" {
			stats, err := dom.BlockStats(disk.Target)
			if err != nil {
				continue
			}
			totalRead += uint64(stats.RdBytes)
			totalWrite += uint64(stats.WrBytes)
		}
	}

	metrics.DiskReadBytes = totalRead
	metrics.DiskWriteBytes = totalWrite
	return nil
}

func (s *vmService) collectNetworkStats(dom *libvirt.Domain, metrics *domain.VMMetrics) error {
	xmlData, err := dom.GetXMLDesc(0)
	if err != nil {
		return err
	}

	config, err := s.xmlBuilder.ParseVMXML(xmlData)
	if err != nil {
		return err
	}

	vmConfig := &domain.VMConfig{
		Networks: config.Networks,
	}

	return s.updateNetworkMetrics(context.Background(), dom, vmConfig, metrics)
}

// updateNetworkMetrics 更新网络性能指标
func (s *vmService) updateNetworkMetrics(ctx context.Context, dom *libvirt.Domain, config *domain.VMConfig, metrics *domain.VMMetrics) error {
	if config.Networks == nil {
		return nil
	}

	var totalRx, totalTx uint64
	for _, net := range config.Networks {
		if net.MAC != "" {
			stats, err := dom.InterfaceStats(net.MAC)
			if err != nil {
				continue
			}
			totalRx += uint64(stats.RxBytes)
			totalTx += uint64(stats.TxBytes)
		}
	}

	metrics.NetRxBytes = totalRx
	metrics.NetTxBytes = totalTx
	return nil
}
